/**
******************************************************************************
  * @file           : UdpService.h
  * @author         : sally
  * @brief          : None
  * @attention      : None
  * @date           : 24-11-09
  ******************************************************************************
  */


#ifndef UDPSEVICE_H
#define UDPSEVICE_H

#include <future>
#include <memory>
#include <string>
#include <thread>
#include <unordered_map>
#include <vector>
#include <uv.h>
#include <iostream>

#define ON 1

/**
 *  这个类新增了，解析域名的操作，然后就根据解析出来的域名进行发送
 */
namespace droneswarm
{
    struct AsyncSendRequest
    {
        uv_buf_t buffer;
        uv_udp_send_t send_req;
        uv_udp_t* send_socket;
        std::shared_ptr<std::string> message;
        std::promise<bool> promise;
        struct sockaddr* addr;
        // uint16_t port;  //我们在进行根据域名进行udp的数据发送时，需要发送端口到异步的回调函数中，通过这种方式发送

        ~AsyncSendRequest()
        {
            if (addr)
            {
                delete addr;
                addr = nullptr;
            }

            //这里不删除，因为真正的删除不在这里而是在udpInfo_struct里面，在这里删除会导致错误
            // if (send_socket)
            // {
            //     delete send_socket;
            //     send_socket = nullptr;
            // }
        }
    };

    struct udpInfo_struct
    {
        uv_loop_t* loop;
        uv_udp_t* socket;
        struct sockaddr_in addr;
        uint16_t load;
        uv_async_t* asyc;

        ~udpInfo_struct()
        {
            if (loop)
            {
                uv_loop_close(loop);

                loop = nullptr;
            }
            if (socket)
            {
                uv_close((uv_handle_t*)socket, on_close);
                socket = nullptr;
            }
            if (asyc)
            {
                uv_close((uv_handle_t*)asyc, on_close);
                asyc = nullptr;
            }
        }

        static void on_close(uv_handle_t* handle)
        {
            std::cout << "Async handle closed" << std::endl;
            delete handle;
        }
    };

    //在静态函数中使用锁的话，那么这个锁就不能是类的锁
    static std::mutex mutex;

    class UdpService
    {
    private:
        typedef std::function<void()> CallBack;
    public:
        UdpService(const std::string& ip, const uint16_t& port, uint8_t threadNum);
        ~UdpService();
        void start();
        void stop();
        bool send_message(const std::string& ip, const uint16_t& port, const std::string& message);
        bool send_messageByDomainName(const std::string& domain_name, const uint16_t port, const std::string& message);
        void setHelloHander(CallBack &&helloHandler)
        {
            helloHandler_ = helloHandler;
        }

    private:
        std::shared_ptr<struct udpInfo_struct> createUdpInfo(const std::string& ip, const uint16_t& port);
        void run_loop();
        static void alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buff);
        static void on_handle_received_data(uv_udp_t* socket, ssize_t nread, const uv_buf_t* buff,
                                            const struct sockaddr* addr, unsigned flags);
        static void on_async_send(uv_async_t* handle);
        static void on_send_request(uv_udp_send_t* req, int status);
        static void on_resolved(uv_getaddrinfo_t* req, int status, struct addrinfo* res);
        struct sockaddr* convert_Ip_Port_sockaddr(const std::string& ip, const uint16_t& port, int AF);
        std::shared_ptr<udpInfo_struct> Minimum_load();



    private:
        std::string m_ip;
        uint16_t m_port;
        uint8_t m_threadNums;
        std::vector<std::thread> m_threads;
        std::unordered_map<std::thread::id, std::shared_ptr<udpInfo_struct>> udpInfoMap;
        CallBack helloHandler_;
    };
} // droneswarm

#endif //UDPSEVICE_H
